home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tech Arsenal 1
/
Tech Arsenal (Arsenal Computer).ISO
/
tek-01
/
sox.zip
/
PRED.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-06-15
|
5KB
|
251 lines
/*
* July 5, 1991
* Copyright 1991 Lance Norskog And Sundry Contributors
* This source code is freely redistributable and may be used for
* any purpose. This copyright notice must be maintained.
* Lance Norskog And Sundry Contributors are not responsible for
* the consequences of using this software.
*/
/*
* Sound Tools prediction-correction compression effect file.
* Experiment with various simple equation systems.
*
* This is not ready for prime time. It's here for research purposes.
* Sox will hang if you run this as is. Define D0 or D1, recompile,
* and try compressing the output with 'compress' and 'pack'.
*
* Inspired by 2D PC gem in Graphics Gems II.
*/
#include "st.h"
#define D0 /* output difference between successive samples */
/* #define D1 /* guess by extending slope of last two samples */
/* #define D2 /* extend second derivate and guess signal turn */
/* Autocorrelation isn't worth pursuing. D2 should do an excellent job */
/* Private data for Prediction-Correction state machine */
typedef struct predstuff {
int direction; /* 0 for compress, 1 for decompress */
int first; /* first time through? */
u_i error; /* average error output */
int clipped; /* # of clipped error values */
#ifdef D0
long in[1]; /* previous input sample */
#endif
#ifdef D1
long in[2]; /* previous input samples */
#endif
} *pred_t;
long pred_init(), pred_ict(), pred_next();
/*
* Process options
*/
pred_getopts(effp, n, argv)
eff_t effp;
int n;
char **argv;
{
pred_t pred = (pred_t) effp->priv;
if ((n != 1) ||
(strcmp(argv[0], "-c") && strcmp(argv[0], "-d")))
fail("Linp compression requires in or out options.");
pred->direction = strcmp(argv[0], "-c");
}
/*
* Start processing
*/
pred_start(effp)
eff_t effp;
{
pred_t pred = (pred_t) effp->priv;
pred->error = 0;
pred->first = 1;
pred->clipped = 0;
}
/*
* Process according to compression direction.
* Both loops use the same state machine,
* but feed it from different streams.
*/
/*
* If first time, emit first two samples.
* Then,
*/
pred_flow(effp, ibuf, obuf, isamp, osamp)
eff_t effp;
long *ibuf, *obuf;
int *isamp, *osamp;
{
int len, done;
pred_t pred = (pred_t) effp->priv;
register long predict, error;
char c;
unsigned char uc;
short s;
unsigned short us;
long l;
unsigned long ul;
float f;
double d;
done = 0;
if (pred->first) {
done = pred_init(effp, ibuf, obuf);
ibuf += done;
obuf += done;
pred->first = 0;
}
len = ((*isamp > *osamp) ? *osamp : *isamp);
if (done > len) /* it can't happen here */
fail("Prediction effect: not enough samples?");
if (pred->direction) { /* decompress */
for(; done < len; done++) {
/* reconstitute sample from prediction and error */
predict = pred_ict(effp);
error = *ibuf;
pred_next(effp, predict + error);
pred->error = pred->error/2 + abs(error)/2;
*obuf++ = predict + error;
ibuf++;
}
} else { /* compress */
for(; done < len; done++) {
/* generate sample from prediction and error */
predict = pred_ict(effp);
error = *ibuf - predict;
pred->error = pred->error/2 + abs(error)/2;
if (predict + error != *ibuf)
pred->clipped++;
pred_next(effp, *ibuf);
ibuf++;
*obuf++ = error;
}
}
}
/*
* Linear Prediction state machine part A.
*
* Initialize from buffer. Return number of samples processed.
* It will be the same for input and output streams.
*/
long
pred_init(effp, ibuf, obuf)
eff_t effp;
long *ibuf, *obuf;
{
pred_t pred = (pred_t) effp->priv;
long avg, ret;
/*
* This is bogus!
* Just pretend samples in negative time are 0, make a first few
* weird guesses.
*/
#ifdef D0
/* same for compress and decompress */
pred->in[0] = *obuf++ = *ibuf++;
return 1;
#endif
#ifdef D1
/* same for compress and decompress */
pred->in[0] = *obuf++ = *ibuf++;
pred->in[1] = *obuf++ = *ibuf++;
return 2;
#endif
}
/*
* Linear Prediction state machine part B.
*
* Emit a predicted sample.
*/
long
pred_ict(effp)
eff_t effp;
{
pred_t pred = (pred_t) effp->priv;
long avg, ret;
#ifdef D1
avg = (pred->in[0]/2 + pred->in[1]/2);
return pred->in[1] + (pred->in[1] - avg);
#endif
#ifdef D0
/* Assume flat data */
return pred->in[0];
#endif
}
/*
* Linear Prediction state machine, part C.
*
* Process next sample.
*/
long
pred_next(effp, samp)
eff_t effp;
long samp;
{
pred_t pred = (pred_t) effp->priv;
long avg, ret;
#ifdef D1
pred->in[0] = pred->in[1];
pred->in[1] = samp;
#endif
#ifdef D0
/* Assume flat data */
pred->in[0] = samp;
#endif
}
/*
* Do anything required when you stop reading samples.
* Don't close input file!
*/
pred_stop(effp)
eff_t effp;
{
pred_t pred = (pred_t) effp->priv;
int error;
int size;
/* XXX Or should it always be the input size? */
if (pred->direction)
size = effp->ininfo.size;
else
size = effp->outinfo.size;
switch(size) {
case WORD:
error = pred->error / (1 << 16);
break;
case BYTE:
error = pred->error / (1 << 24);
break;
default:
error = pred->error;
break;
}
/* nothing to do */
fprintf(stderr, "Prediction\n\tAverage Error outputs: %d\n", error);
fprintf(stderr, "\tClipped error outputs: %d\n", pred->clipped);
}